<template>
	<view class="left clearfix bai" style="height:100%;">
		<children-top title="口播视频" page="/pages/index/index"></children-top>
		
		<view class="tim-content left clearfix">
			<view class="tim-left left clearfix">
				<view class="tim-left-title left clearfix">
					输入配音文案
					
					<label style="float:right;margin-right:20px;" title="作品列表" @click="navigatTo('/pages/works/works')">
						<uni-icons type="icon-component-full" size="25" color="#2979ff" custom-prefix="iconfont"></uni-icons>
					</label>
				</view>
				
				<create-textarea :chapter="chapterData" :fontTotalNumber="500" @change="getContent"></create-textarea>
			</view>
			<view class="tim-right right clearfix relative">
				<view class="tim-right-title left clearfix relative">
					视频文件
					<view class="tim-right-sucai right">
						<label>
							<uni-icons type="icon-wodezuopin" size="20" color="#666" custom-prefix="iconfont"></uni-icons>
						</label>
						<label>
							素材库
						</label>
						
					</view>
				</view>
				<view class="tim-right-yinse left clearfix" @click="uploadVideo()" v-if="percent < 100 && !video.url">
					<view class="tim-right-video left clearfix" v-if="percent == 0">
						<uni-icons type="icon-shangchuan5" size="30" color="#18bc37" custom-prefix="iconfont"></uni-icons>
					</view>
					<view class="tim-right-video left clearfix" v-if="percent > 0" style="margin-top:60px;margin-left:calc((100% - 90px)/2 - 5px);">
						<zmt-circular-progress :percent="percent"></zmt-circular-progress>
					</view>
				</view>
				
				<view class="tim-right-yinse left clearfix relative" v-if="percent == 100 || video.url">
					<view class="tim-right-video-del absolute" style="cursor:pointer;" @click="removeVideo()">
						<uni-icons type="closeempty" size="14" color="#fff"></uni-icons>
					</view>
					<video :src="video.url" :style="'width:'+videoWidth+'px;height:'+videoHeight+'px;margin-left:calc((100% - '+videoWidth+'px)/2);margin-top:calc((200px - '+videoHeight+'px)/2);border-radius:5px;'" :autoplay="true"></video>
				</view>
				
				
				<view class="tim-right-title left clearfix relative">
					配音设置
				</view>
				
				<view class="tim-type-box left clearfix relative">
					<view class="tim-type-item left" @click="timbreType = 1" :style="timbreType==1?'background:#fff;border-radius:7px;box-shadow: 0 0 4px 0 rgba(0, 0, 0, .15);color:#333;font-weight:500;':'background:none;border-radius:0;box-shadow: none;'">
						复刻声音
					</view>
					
					<view class="tim-type-item left" @click="timbreType = 2" :style="timbreType==2?'background:#fff;border-radius:7px;box-shadow: 0 0 4px 0 rgba(0, 0, 0, .15);color:#333;font-weight:500;':'background:none;border-radius:0;box-shadow: none'">
						智能配音
					</view>
					
				</view>
				
				<view class="tim-item-content left clearfix">
					
					<view class="tim-yinse-box left clearfix" v-if="timbreType == 2">
						<timbre @confirm="selectTimbre"></timbre>
					</view>
					
					<view class="tim-yinse-box left clearfix" v-if="audio && audio.url">
						<zmt-audio :audio="audio" @removeAudio="removeAudio"></zmt-audio>
					</view>
					
					<view class="tim-yinse-box left clearfix" v-if="timbreType == 1">
						<cosy-voice :showContent = "voiceContent" @setContent="setContent" @success ="cosyVoice" :video="video"></cosy-voice>
					</view>
				
				</view>
				<view class="tim-submit left clearfix absolute" v-if="!audio || !audio.src" @click="createAudio()">
					合成音频
				</view>
				
				
				
				<view class="tim-submit left clearfix absolute" v-if="audio && audio.url && video && video.url" @click="createVideo()">
					生成视频
				</view>
				
				
			</view>
		</view>
		
		<zmt-modal title="声音合成中" :show="modalShow" @close="modalShow = false" :content="modalContent"></zmt-modal>
	</view>
</template>
<style>
	body,uni-page-body{height:100%;}
	uni-slider .uni-slider-handle-wrapper{position: relative;
    height: 4px;
    border-radius: 5px;
    background-color: #e9e9e9;
    cursor: pointer;
    transition: background-color 0.3s ease;
    -webkit-tap-highlight-color: transparent}
</style>
<style scoped>
	.tim-item-content{width:100%;height:36%;overflow: auto;}
	.tim-right-sucai:hover{color:#2979ff;}
	.tim-right-sucai label{float:left;margin-right:5px;font-size:13px;}
	.tim-right-sucai{margin-right:10px;}
	.tim-right-video-del{width:25px;height:25px;background:rgba(100,100,100,.9);text-align: center;line-height:25px;right:-10px;top:-10px;border-radius: 50%;}
	.tim-yinse-box{width:calc(100% - 40px);margin-left:20px;margin-top:30px;}
	.tim-right-video{width:90px;height:32px;margin-left:calc((100% - 90px)/2);font-size:12px;line-height:32px;text-align: center;margin-top:calc(50%/2);border-radius: 5px;cursor:pointer;}
	.tim-type-item{width:calc(50% - 5px);height:35px;line-height:35px;margin:5px;margin-top:2.5px;margin-left:2.5px;margin-right:2.5px;cursor: pointer;position: relative;text-align: center;transition: color 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);font-size:13px;color:#666;}
	.tim-type-box{width:calc(100% - 40px);margin-left:20px;background-color: rgba(0, 0, 0, 0.04);height:40px;margin-top:20px;border-radius: 7px;}
	.tim-use-box{width:45px;height:45px;border-radius: 50%;border:1px solid #eee;right:20px;top:-13px;}
	.tim-right-play{width:25px;line-height:25px;text-align:center;height:25px;background:rgba(100,100,100, .3);left:10px;top:10px;border-radius: 50%;z-index:100; }
	.tim-right-text{width:100%;line-height:15px;text-align: center;color:#666;font-size:13px;}
	.tim-right-image{width:45px;height:45px;margin:12.5px;border:1px solid #eee;border-radius: 50%;margin-top:5px;margin-bottom:10px;}
	.tim-right-item{width:70px;height:85px;background:#fff;border-radius: 5px;margin:10px;cursor:pointer;border:1px solid #eee;margin-left:9px;margin-right:4px;}
	.tim-submit{width:80%;margin-left:10%;line-height:40px;background-image: linear-gradient(90deg, #4287fe, #298bfe 25%, #0f8ffd 51%, #25b4c1);color:#fff;text-align: center;border-radius: 10px;bottom:30px;left:0;right:0;cursor:pointer;}
	.tim-right-shuxing-item view:last-child{width:calc(100% - 80px);margin-left:20px;line-height:30px;height:30px;margin-top:-10px;}
	.tim-right-shuxing-item view:first-child{width:60px;text-align: center;line-height:30px;font-size:14px;}
	.tim-right-shuxing-item view{float:left;}
	.tim-right-shuxing-item{width:100%;height:30px;line-height:30px;margin-top:20px;}
	.tim-right-shuxing{width:calc(100% - 40px);margin-left:20px;margin-right:20px;margin-top:20px;}
	.tim-right-yinse{width:90%;margin-left:5%;height:200px;border:1px solid #f8f8f8;background-image: url('/static/images/body-bj.png');background-color: rgb(247, 247, 249);border-radius: 10px;margin-top:20px;}
	.tim-right-title{width:calc(100% - 20px);padding-left:20px;margin-top:20px;font-size:14px;}
	.tim-left-title{width:calc(100% - 20px);padding-left:20px;color: rgb(21, 27, 38);font-size: 18px;font-weight: 500;line-height: 28px;margin-top:20px;}
	.tim-right{width:400px;height:100%;background:#fff;border-radius: 15px;}
	.tim-left{width:calc(100% - 420px);height:100%;background:#fff;border-radius: 15px;}
	.tim-content{width:96%;height:calc(100% - 110px);margin-left:2%;margin-top:70px;}
</style>

<script>
	var db = uniCloud.database();
	var aliyun = uniCloud.importObject('aliyun',{customUI:true});
	var application = uniCloud.importObject('application',{customUI:true});
	export default {
		data() {
			return {
				showContent:{
					title:'暂无声音'
				},//复刻完以后展示的内容
				modalShow:false,
				modalContent:'',//弹窗内容
				timbreType:1,//音色分类
				pitch:1,//语调
				volume:100,//音量
				rate:1,//语速
				timbre:[],
				innerAudioContext:null,//音频播放数据
				audioItem:{},//正在播放的数据
				currentPlayAudioIndex:null,//当前正在播放的index
				currentPlayAudioStatus:null,//当前播放状态
				chapterId:'',
				userinfo:{},//登录用户信息
				chapterData:{},
				currentTimbre:{},//当前使用的音色
				content:'',
				percent:0,//上传视频进度
				video:{},//视频信息
				videoWidth:null,//视频宽度
				videoHeight:null,//视频宽度
				modalContent:'声音提取中',
				voiceContent:{},
				audio:null
			}
		},
		watch:{
			"timbreType"(val){
				if(val == 1){
					
				}else if(val == 2){
					that.getStorageTimbre();
				}
			}
		},
		created() {
			var that = this;
			that.getTimbre();
			uni.getStorage({
				key:'login-userinfo',
				success:function(res){
					var userinfo = res.data;
					if(userinfo && userinfo._id){
						that.userinfo = userinfo;
						that.getTimbreFromUserinfo(userinfo._id);
						//查询出缓存的视频
						that.getCache('oral-video'+userinfo._id,'video');
						//查询出缓存的音频
						that.getCache('oral-audio'+userinfo._id,'audio');
					}else{
						uni.navigateTo({
							url: '/pages/index/index'
						});
					}
				},
				fail() {
					uni.navigateTo({
						url: '/pages/index/index'
					});
				}
			});
			
			that.getStorageTimbre();
		},
		onLoad(e) {
			if(e && e.chapter){
				this.chapterId = e.chapter;
				//查询出默认章节信息
				this.getChapterById(e.chapter);
			}
		},
		methods: {
			//获取缓存的音色
			getStorageTimbre(){
				var that = this;
				uni.getStorage({
					key:'current-timbre',
					success:function(res){
						if(res && res.data){
							that.currentTimbre = res.data;
						}else{
							that.currentTimbre = this.timbre[0];
						}
					},
					fail() {
						that.currentTimbre = this.timbre[0];
					}
				})
			},
			//选择完音色以后
			selectTimbre(e){
				this.currentTimbre = e;
			},
			//跳转到作品页面
			navigatTo(url){
				uni.navigateTo({
					url:url
				})
			},
			//根据key查询出缓存的视频文件
			getCache(key,type){
				var time = new Date().getTime();
				var that = this;
				uni.getStorage({
					key:key,
					success(res) {
						var data = res.data;
						var video = data.data;
						if(type == 'video'){
							if(time < data.expire){
								that.video = video;
								if(video.width > video.height){
									that.videoWidth = 150;
									that.videoHeight = video.height * (150/video.width);
								}else{
									that.videoHeight = 180;
									that.videoWidth = video.width * (180/video.height);
								}
							}
						}else if(type == 'audio'){
							if(time < data.expire){
								that.audio = video;
							}
						}
						
					}
				})
			},
			//生成视频
			createVideo(){
				var that = this;
				var video = this.video;
				var audio = this.audio;
				if(!video || !video.url){
					uni.showToast({
						title:'请上传一段视频',
						icon:'none'
					})
					
					return false;
				}
				
				if(!audio || !audio.url){
					uni.showToast({
						title:'请先合成音频',
						icon:'none'
					})
					
					return false;
				}
				
				var data = {
					model:'videoretalk',
					input:{
						video_url:video.url,
						audio_url:audio.url
					},
					parameters:{
						video_extension:true
					}
				};
				
				aliyun.getVideoTask(data).then(res=>{
					var task_id = res.result.output.task_id;
					if(task_id){
						var userinfo = that.userinfo;
						var addData = {
							app_title:'口播视频',
							app_id:'676f59761c90b6b556f1dde4',
							uid:userinfo._id,
							content:that.content,
							task_id:task_id,
							size:this.video.width+'*'+this.video.height,
							type:'oral',
							task_status:'PENDING',
							task_status_text:'处理中',
							audio_url:audio.src,
							create_date:new Date().getTime()
							
						}
						
						db.collection('create_result').add(addData).then(addRes=>{
							console.log('添加结果',addRes);
							uni.redirectTo({
								url: '/pages/works/works'
							});
						}).catch(err=>{
							console.log('入库失败',err);
						});
					}
					
				}).catch(err=>{
					console.log('任务创建失败',err);
					uni.showToast({
						title:'任务创建失败',
						icon:'none',
						duration:2000
					})
				});
				
				
				
			},
			//删除音频文件
			removeAudio(e){
				var that = this;
				if(e == true){
					this.audio = {}
					uni.removeStorage({
						key:'oral-audio'+that.userinfo._id
					})
				}
			},
			//查询出最近一次复刻的声音
			getTimbreFromUserinfo(uid){
				db.collection('digital_history').where({uid:uid}).orderBy('_id desc').get({getOne:true}).then(res=>{
					var data = res.result.data;
					this.voiceContent = data;
				});
			},
			//添加到素材库
			addToMaterial(data){
				data.uid = this.userinfo._id;
				db.collection('material').add(data);
			},
			//设置弹窗内容
			setContent(e){
				this.modalShow = e.show;
				this.modalContent = e.message;
			},
			//复刻
			cosyVoice(audioSrc){
				var that = this;
					this.modalShow = true;
					this.modalContent = '声音复刻中···';
					var data = {
						model:'voice-enrollment',
						input: {
						    action: "create_voice",
						    target_model: "cosyvoice-v1",
						    prefix: "mofang",
						    url: audioSrc
						}
					}
					aliyun.setCosyVoice(data).then(res=>{
						console.log('复刻结果',res);
						if(res.result && res.result.output && res.result.output.voice_id){
						 var voiceName = res.result.output.voice_id;
						that.modalContent = '声音保存中···';
						// 	//保存到数据库
						var history = {
						 	uid:that.userinfo._id,
						 	title:'复刻我的声音',
						 	type:'audio-fuke',
						 	voice_name:voiceName,
							audio_url:audioSrc
						};
							db.collection('digital_history').add(history).then(addRes=>{
								that.modalContent = '复刻成功';
								setTimeout(function(){
									that.modalShow = false;
								},1000);
								that.showContent =history;
							})
						}else{
							var code = res.result.code;
							var errMsg = '';
							switch(code){
								case 'BadRequest.UnsupportedFileFormat':
								errMsg = '音频文件格式不支持';
								break;
								case 'Audio.DecoderError':
								errMsg = '音频文件解码失败';
								break;
								case 'Audio.AudioShortError':
								errMsg = '音频内无足够的有效语音';
								break;
								case 'Audio.FileSizeExceed':
								errMsg = '文件大小超过限制10MB';
								break;
								case 'Audio.AudioRateError':
								errMsg = '文件采样率不支持，要求16KHz 及以上';
								break;
								case 'Audio.AudioSilentError':
								errMsg = '音频有效时间太短，要求10秒及以上';
								break;
								case 'InternalError':
								errMsg = '音频文件不规范，有杂音或者声音忽高忽低';
								break;
							}
							
							if(res.result.message == 'audio snr error!'){
								errMsg = '提取的音频背景噪音太大';
							}
							uni.showToast({
								title:errMsg,
								icon:'none',
								duration:4000
							})
							that.step = 1;
							that.uploadAudioProgessText = '上传中，请稍后';
							that.uploadProgress = 0;
							that.startSound = false;
						}
						
					}).catch(err=>{
						console.log('复刻失败',err);
						application.createLog({
							type:'复刻音色',
							content:'音色复刻失败,原因:'+JSON.stringify(err)
						})
					})
				
				
				
			},
			//删除已上传的视频
			removeVideo(){
				this.video = {};
				this.percent = 0;
			},
			//上传视频
			uploadVideo(){
				var that = this;
				uni.chooseVideo({
					sourceType: ['album'],
					success: function (res) {
					var  tempFilePath = res.tempFilePath;
					var fileName = that.generateUUIDWithExtensionFromFileName(res.name);
					var video = {
						duration:Math.ceil(res.duration),//时长
						width:res.width,//宽度
						height:res.height,//高度
						size:res.size,//大小
						title:res.name,//名称
					}
					
					if(video.duration > 120){
						uni.showToast({
							title:'视频不可超过2分钟',
							icon:'none',
							duration:2000
						})
						
						return false;
					}
					if(res.width > res.height){
						that.videoWidth = 150;
						that.videoHeight = res.height * (150/res.width);
					}else{
						that.videoHeight = 180;
						that.videoWidth = res.width * (180/res.height);
					}
					
					that.video = video;//视频信息
					uniCloud.uploadFile({
					        filePath: tempFilePath,
					        cloudPath: fileName,
					        onUploadProgress: function(progressEvent) {
					          var percentCompleted = Math.round(
					            (progressEvent.loaded * 100) / progressEvent.total
					          );
							  
							  that.percent = percentCompleted;
					        },
					        success(res) {
								that.video.url = res.fileID;
								video.url = res.fileID;
								video.type = "video";
								delete video.src;
								//保存为素材
								that.addToMaterial(video);
								//将视频缓存1小时，防止刷新后丢失
								that.setCache('oral-video'+that.userinfo._id,that.video);
							}
					      });
					}
				});
			},
			//缓存内容
			setCache(key,data){
				var time = new Date().getTime();
				uni.setStorage({
					key:key,
					data:{
						expire:time + 3600000,//过期时间为1小时
						data:data
					}
				})
			},
			//带有后缀名的uuid
			generateUUIDWithExtensionFromFileName(fileName) {
			    const lastDotIndex = fileName.lastIndexOf('.');
			    let extension = '';
			    if (lastDotIndex !== -1) {
			        extension = fileName.slice(lastDotIndex + 1);
			    }
			    let uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
			        let r = Math.random() * 16 | 0;
			        let v = c === 'x' ? r : (r & 0x3 | 0x8);
			        return v.toString(16);
			    });
			    if (extension) {
			        return `${uuid}.${extension}`;
			    }
			    return uuid;
			},
			//生成音频文件
			createAudio(){
					var that = this;
					var content = this.content;
					if(this.timbreType == 1){
						var timbre = this.voiceContent;
					}else if(this.timbreType == 2){
						var timbre = this.currentTimbre;
						timbre.voice_name = timbre.voice;
					}
					var length = content.length;
					if(!content){
						uni.showToast({
							title:'请输入文本内容',
							icon:'none',
							duration:2000
						})
						
						return false;
					}
					
					if(length > 500){
						uni.showToast({
							title:'当前字数为'+length+',超出了500字',
							icon:'none',
							duration:2000
						})
						
						return false;
					}
					that.modalShow  = true;
					that.modalContent = '生成中···';
					var fileName = that.generateUUID();
					var data = {
						text:content,//合成文本
						voice:timbre.voice_name,//音色
						volume:100,//音量
						rate:1,//语速100
						pitch:1,//语调,
						fileName:fileName
					}
							//异步发送给接口
							aliyun.getCosyVoiceFromPhp(data).then(res=>{
								that.modalShow  = false;
								if(res.code == 200){
									
									var audioSrc = res.result.data.result;
										that.audio = {
											url:audioSrc,
											autoPlay:true,
											type:'audio',
											title:that.content.substring(0,20),
											uid:that.userinfo._id
										}
									
									//缓存
									that.setCache('oral-audio'+that.userinfo._id,that.audio);
									
									
								}
								
							});
			},
						
			//uuid
			generateUUID() {
			    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
			        var r = Math.random() * 16 | 0,
			            v = c === 'x' ? r : (r & 0x3 | 0x8);
			        return v.toString(16);
			    });
			},
			//获取内容
			getContent(text){
				this.content = text;
			},
			//点击使用音色以后
			setSelectTimbre(item,index){
				var that = this;
				//把当前使用的音色缓存起来，以便以后继续使用
				uni.setStorage({
					key:'current-timbre',
					data:item,
					success() {
						that.currentTimbre = item;
					}
				})
			},
			//查询出默认章节信息
			getChapterById(id){
				if(id){
					db.collection('timbre_title').where({_id:id}).get({getOne:true}).then(res=>{
						var data = res.result.data;
						this.chapterData = data;
					});
				}
				
			},
			//设置播放音频
			setPlay(item,act,index){
				var that = this;
				if(item.audio_url != this.audioItem.audio_url){
					if(that.innerAudioContext){
						that.innerAudioContext.stop();
					}
					var innerAudioContext = uni.createInnerAudioContext();
					this.innerAudioContext = innerAudioContext;
					this.audioItem = item;
					innerAudioContext.src = item.audio_url;
					innerAudioContext.autoplay = true;
				}else{
					var innerAudioContext = this.innerAudioContext;
				}
				
				if(act == 'play'){
					innerAudioContext.play();
					innerAudioContext.onPlay(()=>{
						that.currentPlayAudioIndex = index;
						that.currentPlayAudioStatus = 'play';
					});
				}else if(act == 'pause'){
					innerAudioContext.pause();
					that.currentPlayAudioStatus = 'pause';
				}
				
				innerAudioContext.onEnded(()=>{
					that.currentPlayAudioStatus = 'pause';
				});
			},
			//查询出音色
			getTimbre(){
				db.collection('timbre').where({type:'cosyvoice'}).orderBy('_id desc').get().then(res=>{
					var data = res.result.data;
					this.timbre = data;
				});
			}
		}
	}
</script>

